{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ⅰ.ES6~POP\n",
    "\n",
    "代码示例：<a href=\"https://github.com/lotapp/BaseCode/tree/master/javascript/1.ES6\" target=\"_blank\">https://github.com/lotapp/BaseCode/tree/master/javascript/1.ES6</a>\n",
    "\n",
    "在线演示：<https://github.lesschina.com/js/1.base/ES6与PY3.html>\n",
    "\n",
    "ES6现在浏览器基本上都支持了，可以收一波韭菜了～（关键移动端都支持了）\n",
    "\n",
    "## 1.变量\n",
    "\n",
    "### 验证\n",
    "\n",
    "1. `var`：可以重复定义，不能限制修改，没有块级作用域（和Python差不多）\n",
    "2. `let`：不可以重复定义，相当于C#的变量，块级作用域（以后var全部换成let）\n",
    "3. `const`：不可以重复定义，相当于C#的常量，块级作用域\n",
    "\n",
    "### 可以重复定义的验证\n",
    "\n",
    "1.**var可以重复定义**\n",
    "```javascript\n",
    "var a1 = 12; // 定义了一个a变量\n",
    "// ...写了若干代码\n",
    "var a1 = 5; // 然后又重新定义了一个a，这时候可能就有潜在bug了\n",
    "\n",
    "console.log(a1); // 5\n",
    "```\n",
    "\n",
    "2.**let不可以重复定义，相当于C#的变量**（以后var全部换成let）\n",
    "```javascript\n",
    "let a2 = 12;\n",
    "let a2 = 5;\n",
    "\n",
    "// 标识符a已经被声明\n",
    "console.log(a2); // Identifier 'a2' has already been declared\n",
    "```\n",
    "\n",
    "3.**const：不可以重复定义，相当于C#的常量**\n",
    "```javascript\n",
    "const a3 = 12;\n",
    "const a3 = 5;\n",
    "\n",
    "// 标识符a已经被声明\n",
    "console.log(a3); // Identifier 'a3' has already been declared\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "### 可以被修改的验证\n",
    "\n",
    "1.**`var`可以修改**\n",
    "```javascript\n",
    "var a = 2;\n",
    "a = 3;\n",
    "\n",
    "// var 可以修改\n",
    "console.log(a); //3\n",
    "```\n",
    "\n",
    "2.**`let`可以修改**\n",
    "```javascript\n",
    "let b = 2;\n",
    "b = 3;\n",
    "\n",
    "// let可以修改\n",
    "console.log(b);\n",
    "```\n",
    "\n",
    "3.**`const`不可以修改**\n",
    "```javascript\n",
    "const c = 12;\n",
    "c = 5;\n",
    "\n",
    "// 不能赋值给常量变量\n",
    "console.log(c); // Assignment to constant variable.\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "### 验证作用域\n",
    "\n",
    "1.**var没有块级作用域**\n",
    "```javascript\n",
    "if(1<2){\n",
    "    var b1 = 1;\n",
    "}\n",
    "\n",
    "// var没有块级作用域\n",
    "console.log(b1); // 1\n",
    "```\n",
    "2.**let复合正常变量特性**\n",
    "```javascript\n",
    "// 和我们平时使用差不多了\n",
    "if(1<2){\n",
    "    let b2 = 1;\n",
    "}\n",
    "\n",
    "// ReferenceError: b2 is not defined\n",
    "console.log(b2); // b2 没有定义\n",
    "```\n",
    "3.**更严格的const就更不说了**\n",
    "```javascript\n",
    "if(1<2){\n",
    "    const b3 = 1;\n",
    "}\n",
    "\n",
    "// ReferenceError: b3 is not defined\n",
    "console.log(b3); // b3 没有定义\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "\n",
    "### Python3\n",
    "\n",
    "**变量没有修饰符的，直接定义，全局变量`global`引用即可**\n",
    "\n",
    "1.**var变量和Python类似**\n",
    "```py\n",
    "if 1 < 2:\n",
    "    b = 1\n",
    "print(b) # 1\n",
    "```\n",
    "2.**全局变量建议`global`引用一下**\n",
    "```py\n",
    "age = 20\n",
    "\n",
    "def test():\n",
    "    global age\n",
    "    print(age) # 20\n",
    "```\n",
    "\n",
    "### 结论：(以后`var`全部换成`let`)\n",
    "1. `var`：可以重复定义，不能限制修改，没有块级作用域（和Python差不多）\n",
    "2. `let`：不可以重复定义，相当于C#的变量，块级作用域（以后var全部换成let）\n",
    "3. `const`：不可以重复定义，相当于C#的常量，块级作用域"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.解构赋值\n",
    "\n",
    "这个特性不管是`C#`还是`ES6`都是从`Python`那借鉴过来的，特点：\n",
    "1. 左右两边结构一样\n",
    "2. 定义和赋值同时完成\n",
    "\n",
    "### 基础\n",
    "\n",
    "简单版：\n",
    "```javascript\n",
    "let [a,b,c] = [1,2,3];\n",
    "console.log(a,b,c); // 1 2 3\n",
    "```\n",
    "\n",
    "变化版：\n",
    "```javascript\n",
    "let {a,b,c} = {a:1,b:2,c:3}; // json格式对应也行\n",
    "console.log(a,b,c); // 1 2 3\n",
    "```\n",
    "PS：把后面改成`{a1:1,b1:2,c1:3}`就变成`undefined undefined undefined`\n",
    "\n",
    "复杂版：\n",
    "```javascript\n",
    "let [x, { a, b, c }, y] = [4, { a: 1, b: 2, c: 3 }, 5];\n",
    "console.log(a, b, c, x, y); // 1 2 3 4 5\n",
    "```\n",
    "\n",
    "### 验证\n",
    "\n",
    "1. **左右两边结构需要一样**\n",
    "```javascript\n",
    "// 这种就不行，格式得对应（左边3，右边5个 ==> over）\n",
    "let [x, { a, b, c }, y] = { a: 1, b: 2, c: 3, x: 4, y: 5 };\n",
    "console.log(a, b, c, x, y); // 未捕获的TypeError：{...}不可迭代\n",
    "```\n",
    "\n",
    "2. **定义和赋值同时完成**\n",
    "```javascript\n",
    "let [a, b, c];\n",
    "[a, b, c] = [1, 2, 3];\n",
    "// 未捕获的SyntaxError：在解构声明中缺少初始化程序\n",
    "console.log(a, b, c);\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.函数系\n",
    "\n",
    "### 3.1.箭头函数（匿名函数）\n",
    "\n",
    "以前写法：\n",
    "```javascript\n",
    "function (参数,参数){\n",
    "    函数体\n",
    "}\n",
    "```\n",
    "简化写法：\n",
    "```javascript\n",
    "(参数,参数) => {\n",
    "    函数体\n",
    "}\n",
    "\n",
    "参数 => {\n",
    "    函数体\n",
    "}\n",
    "\n",
    "参数 => 表达式\n",
    "```\n",
    "\n",
    "**举个例子**：\n",
    "```javascript\n",
    "function add(x, y) {\n",
    "    return x + y;\n",
    "}\n",
    "\n",
    "let add1 = function (x, y) {\n",
    "    return x + y;\n",
    "}\n",
    "\n",
    "let add2 = (x, y) => {\n",
    "    return x + y;\n",
    "}\n",
    "\n",
    "let add3 = (x,y) => x+y;\n",
    "console.log(add(1, 2)); // 3\n",
    "console.log(add1(1, 2)); // 3\n",
    "console.log(add2(1, 2)); // 3\n",
    "console.log(add3(1, 2)); // 3\n",
    "```\n",
    "\n",
    "#### 小验证（`和Net用起来基本上一样`）\n",
    "1. **如果只有一个参数：`()`可以省略**\n",
    "```javascript\n",
    "let get_age = age => {\n",
    "    return age - 2;\n",
    "}\n",
    "console.log(get_age(18)); // 16\n",
    "```\n",
    "2. **如果函数体只有一句话：`{}`可以省略**\n",
    "    - 如果只有一句`return`，那么`return`也可以省略\n",
    "```javascript\n",
    "let get_age = age => age - 2;\n",
    "console.log(get_age(18)); // 16\n",
    "```\n",
    "    - 没有`return`也可以简写\n",
    "```javascript\n",
    "let print_age = age => console.log(age - 2);\n",
    "print_age(18); // 16\n",
    "```\n",
    "\n",
    "PS：**箭头函数会改变`this`（后面会说）**\n",
    "\n",
    "---\n",
    "\n",
    "### 3.2.默认参数\n",
    "\n",
    "```javascript\n",
    "// 原来：\n",
    "function show(a, b, c) {\n",
    "    c = c || 7; // 默认参数\n",
    "    console.log(a, b, c);\n",
    "}\n",
    "// 现在：\n",
    "function show(a, b, c = 7) {\n",
    "    console.log(a, b, c);\n",
    "}\n",
    "\n",
    "show(1, 2); // 1 2 7\n",
    "show(1, 2, 3); // 1 2 3\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "### 3.3.参数展开\n",
    "\n",
    "#### 基本用法\n",
    "\n",
    "举个例子：\n",
    "```javascript\n",
    "let show_args = (a, b, ...args) => console.log(a, b, args);\n",
    "// `...args`是个数组（Python是元组）\n",
    "show_args(1, 2, 3, 4, 5, 6);// 1 2 [3, 4, 5, 6] \n",
    "```\n",
    "\n",
    "#### 小验证\n",
    "\n",
    "1. **`...args`必须是最后一个参数**\n",
    "```javascript\n",
    "let show_args = (a, b, ...args, c) => console.log(a, b, args, c);\n",
    "// Uncaught SyntaxError: Rest parameter must be last formal parameter\n",
    "show_args(1, 2, 4, 5, 6, c = 3); // ...args必须是最后一个参数\n",
    "```\n",
    "\n",
    "PS：**Python里面可以**：\n",
    "```py\n",
    "def show(a, b, *args, c):\n",
    "    print(a, b, args, c)\n",
    "\n",
    "# 1 2 (4, 5, 6) 3\n",
    "show(1, 2, 4, 5, 6, c=3)\n",
    "```\n",
    "\n",
    "#### 扩展用法\n",
    "\n",
    "**案例1**：\n",
    "```javascript\n",
    "let nums = [1, 2, 3, 4];\n",
    "// 解包使用\n",
    "let nums2 = [0, ...nums, 5, 6];\n",
    "// [0,1,2,3,4,5,6]\n",
    "console.log(nums2);\n",
    "```\n",
    "\n",
    "PS：**Python用法类似**：\n",
    "```py\n",
    "# 列表换成元组也一样用\n",
    "num_list = [1,2,3,4]\n",
    "# 不管是列表还是元组，这边需要加*才能解包\n",
    "num_list2 = [0,*num_list,5,6]\n",
    "# [0, 1, 2, 3, 4, 5, 6]\n",
    "print(num_list2)\n",
    "```\n",
    "\n",
    "**案例2**：\n",
    "```javascript\n",
    "let nums = [1, 2, 3, 4];\n",
    "let nums2 = [0, 5, 6];\n",
    "nums.push(...nums2);\n",
    "// [1, 2, 3, 4, 0, 5, 6]\n",
    "console.log(nums);\n",
    "```\n",
    "\n",
    "PS：**Python用法类似**：\n",
    "```py\n",
    "num_list = [1,2,3,4]\n",
    "num_list2 = [0,5,6]\n",
    "# [1, 2, 3, 4, 0, 5, 6]\n",
    "num_list.extend(num_list2)\n",
    "print(num_list)\n",
    "\n",
    "# 如果使用append就是嵌套版列表了\n",
    "# num_list.append(num_list2)\n",
    "# [1, 2, 3, 4, [0, 5, 6]]\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "### 3.4.特殊的this（重要）\n",
    "\n",
    "**普通函数的this ==> 谁调用就是谁（经常变：谁调用是谁）**\n",
    "\n",
    "```javascript\n",
    "function show() {\n",
    "    alert(this); // 1,2,3,4\n",
    "    console.log(this); // [1, 2, 3, 4, show: ƒ]\n",
    "}\n",
    "\n",
    "let arr = [1, 2, 3, 4];\n",
    "arr.show = show;\n",
    "arr.show();\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "**箭头函数的this ==> 在谁的环境下`this`就是谁（不变：当前作用域）**\n",
    "```javascript\n",
    "let arr = [1, 2, 3, 4];\n",
    "arr.show = () => {\n",
    "    alert(this); // [object Window]\n",
    "    console.log(this); // Window\n",
    "}\n",
    "arr.show();\n",
    "```\n",
    "\n",
    "再举个例子：**在document内**\n",
    "```javascript\n",
    "document.onclick = function () {\n",
    "    let arr = [1, 2, 3, 4];\n",
    "    arr.show = () => {\n",
    "        console.log(this); // document\n",
    "    }\n",
    "    arr.show();\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.数组方法\n",
    "\n",
    "**下面几个方法都不会改变原数组**\n",
    "\n",
    "### 4.1.map\n",
    "\n",
    "**映射**，传几个参数进去，出来几个参数。（**不改变数组内容，生成新数组**）\n",
    "\n",
    "#### 基本用法\n",
    "\n",
    "```javascript\n",
    "scor_arr = [100, 28, 38, 64]\n",
    "let results = scor_arr.map(item => item >= 60);\n",
    "\n",
    "// [true, false, false, true]\n",
    "console.log(results); // 不改变scor_arr内容，生成新数组\n",
    "\n",
    "// old：\n",
    "// let results = scor_arr.map(function (item) {\n",
    "//     return item >= 60;\n",
    "// });\n",
    "```\n",
    "\n",
    "#### Python3\n",
    "\n",
    "Python略有不同：(`把函数依次作用在list的每个元素上`)\n",
    "```py\n",
    "scor_list = [100, 28, 38, 64]\n",
    "result_list = map(lambda item: item >= 60, scor_list)\n",
    "\n",
    "# [True, False, False, True] 不改变旧list的值\n",
    "print(list(result_list))\n",
    "```\n",
    "PS：result_list：PY2直接返回list，PY3返回`Iterator`\n",
    "\n",
    "---\n",
    "\n",
    "### 4.2.filter\n",
    "\n",
    "代言词：**过滤**（**不改变数组内容，生成新数组**）\n",
    "\n",
    "#### 基本用法\n",
    "\n",
    "```javascript\n",
    "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n",
    "nums2 = nums.filter(item => item % 2 == 0);\n",
    "\n",
    "// [2, 4, 6, 8, 10]\n",
    "console.log(nums2) // 不改变旧数组的值\n",
    "```\n",
    "\n",
    "#### Python3\n",
    "\n",
    "Python略有不同：(`把函数依次作用在list的每个元素上`)\n",
    "```py\n",
    "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "nums2 = filter(lambda item: item % 2 == 0, nums)\n",
    "\n",
    "# [2, 4, 6, 8, 10] 不改变旧list的值\n",
    "print(list(nums2))\n",
    "```\n",
    "\n",
    "PS：nums2：PY2直接返回list，PY3返回`Iterator`\n",
    "\n",
    "---\n",
    "\n",
    "### 4.3.forEach\n",
    "\n",
    "**不做任何修改，纯粹的遍历**，用法和`net`里面的`ForEach`差不多\n",
    "\n",
    "#### `forEach`没有返回值的验证\n",
    "\n",
    "```javascript\n",
    "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n",
    "let sum = 0;\n",
    "let temp =nums.forEach(item => {\n",
    "    sum += item;\n",
    "});\n",
    "console.log(sum) // 55\n",
    "console.log(temp) // 验证了：forEach 没有返回值\n",
    "```\n",
    "\n",
    "**NetCore**：\n",
    "```csharp\n",
    "var sum = 0;\n",
    "var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n",
    "list.ForEach(item => sum += item);\n",
    "Console.WriteLine(sum); // 55\n",
    "```\n",
    "\n",
    "#### 不会改变原数组的验证\n",
    "\n",
    "```javascript\n",
    "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n",
    "nums.forEach(item => {\n",
    "    item += 1;\n",
    "});\n",
    "\n",
    "// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "console.log(nums); //不会改变nums，仅仅是遍历\n",
    "```\n",
    "\n",
    "**NetCore**：\n",
    "\n",
    "```csharp\n",
    "var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n",
    "list.ForEach(item => item += 1);\n",
    "foreach (var item in list)\n",
    "{\n",
    "    // 12345678910\n",
    "    Console.Write(item); //不会改变list里面的值\n",
    "}\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "### 4.4.reduce\n",
    "\n",
    "代言词：**汇总**，和`map`有点相反，**进去一堆出来一个**\n",
    "\n",
    "#### 基础用法\n",
    "\n",
    "```javascript\n",
    "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n",
    "// x是第一个元素，y是第二个元素\n",
    "nums.reduce((x, y, index) => {\n",
    "    console.log(x, y, index);\n",
    "});\n",
    "```\n",
    "输出：\n",
    "```\n",
    "1 2 1\n",
    "undefined 3 2\n",
    "undefined 4 3\n",
    "undefined 5 4\n",
    "undefined 6 5\n",
    "undefined 7 6\n",
    "undefined 8 7\n",
    "undefined 9 8\n",
    "undefined 10 9\n",
    "```\n",
    "\n",
    "#### 逆推JS执行过程\n",
    "\n",
    "**逆推整个执行过程**：\n",
    "1. x只被赋值一次\n",
    "2. y从第二个值开始往下遍历\n",
    "3. 整个过程只遍历9遍就结束了\n",
    "    - for循环需要10次遍历结束\n",
    "    - y从第二个数开始的，少一次遍历也正常\n",
    "\n",
    "简单说就是按顺序依次执行函数，eg：\n",
    "```javascript\n",
    "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n",
    "result = nums.reduce((x, y) => x + y);\n",
    "console.log(result / nums.length) // 5.5\n",
    "```\n",
    "\n",
    "reduce直接求平均值：（**return**是关键）\n",
    "```\n",
    "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n",
    "let result = nums.reduce((temp, item, index) => {\n",
    "    temp += item;\n",
    "    if (index < nums.length - 1) {\n",
    "        return temp;\n",
    "    } else { // 最后一次，返回平均值即可\n",
    "        return temp / nums.length;\n",
    "    }\n",
    "});\n",
    "console.log(result) // 5.5\n",
    "```\n",
    "\n",
    "#### Python3\n",
    "\n",
    "**reduce就两个参数（`有且仅有`）**\n",
    "\n",
    "`Python`的`Reduce`没`js`的强大，一般都是对列表做一个累积的‘汇总’操作\n",
    "\n",
    "```py\n",
    "import functools\n",
    "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "result = functools.reduce(lambda x, y: x + y, nums)\n",
    "print(result / len(nums)) # 5.5\n",
    "```\n",
    "\n",
    "可以看看执行过程：\n",
    "```py\n",
    "import functools\n",
    "\n",
    "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "result = functools.reduce(lambda x, y: print(x, y), nums)\n",
    "print(result)\n",
    "```\n",
    "输出：\n",
    "```\n",
    "1 2\n",
    "None 3\n",
    "None 4\n",
    "None 5\n",
    "None 6\n",
    "None 7\n",
    "None 8\n",
    "None 9\n",
    "None 10\n",
    "None\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "### 4.5.Array.from\n",
    "\n",
    "通俗讲：**把类数组集合转化成数组**\n",
    "\n",
    "HTML代码：`/BaseCode/javascript/1.ES6/1.array.from.html`\n",
    "\n",
    "```html\n",
    "<!DOCTYPE html>\n",
    "<html>\n",
    "<head>\n",
    "    <meta charset=\"utf-8\" />\n",
    "    <title>Array.from的应用</title>\n",
    "</head>\n",
    "<body>\n",
    "    <style type=\"text/css\">\n",
    "        div {\n",
    "            width: 200px;\n",
    "            height: 200px;\n",
    "            margin-right: 1px;\n",
    "            float: left;\n",
    "        }\n",
    "    </style>\n",
    "    <div></div>\n",
    "    <div></div>\n",
    "    <div></div>\n",
    "</body>\n",
    "</html>\n",
    "```\n",
    "JS部分：(**collection是没有forEach方法的，需要转化成数组**)\n",
    "```javascript\n",
    "window.onload = () => {\n",
    "    let collection = document.getElementsByTagName(\"div\");\n",
    "    Array.from(collection).forEach(item => item.style.background = \"blue\");\n",
    "}\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.JSON系\n",
    "\n",
    "### 键值相同可以只写一个\n",
    "```javascript\n",
    "let [a, b] = [1, 2];\n",
    "json = { a, b, c: 3 };\n",
    "console.log(json); // {a: 1, b: 2, c: 3}\n",
    "\n",
    "// 原来写法\n",
    "// json = { a: a, b: b, c: 3 };\n",
    "```\n",
    "\n",
    "### 函数function可以省略\n",
    "\n",
    "```javascript\n",
    "json = {\n",
    "    a: 1,\n",
    "    b: 2,\n",
    "    show() {\n",
    "        console.log(this.a, this.b);\n",
    "    }\n",
    "};\n",
    "json.show(); // 1 2\n",
    "\n",
    "// 原来写法\n",
    "// json = {\n",
    "//     a: 1,\n",
    "//     b: 2,\n",
    "//     show: function () {\n",
    "//         console.log(this.a, this.b);\n",
    "//     }\n",
    "// };\n",
    "```\n",
    "\n",
    "### 基础复习\n",
    "\n",
    "**`Json`字符串的标准写法**：\n",
    "1. **只能用双引号**\n",
    "2. **所有名字必须用引号包裹**\n",
    "\n",
    "```javascript\n",
    "let str1 = '{ a: 12, b: 5 }'; // 错误\n",
    "let str2 = '{ \"a\": 12, \"b\": 5 }';// 正确\n",
    "let str3 = \"{ 'a': 'abc', 'b': 5 }\";// 错误（单引号）\n",
    "let str4 = '{ \"a\": \"abc\", \"b\": 5 }';// 正确（双引号）\n",
    "\n",
    "// 测试是否为字符串\n",
    "[str1, str2, str3, str4].forEach(str => {\n",
    "    try {\n",
    "        let json = JSON.parse(str);// 转换成JSON对象\n",
    "        console.log(json);\n",
    "    } catch (ex) {\n",
    "        console.log(`字符串：${str}转换发生异常：${ex}`);\n",
    "    }\n",
    "});\n",
    "```\n",
    "输出：\n",
    "```\n",
    "字符串：{ a: 12, b: 5 }转换发生异常：SyntaxError: Unexpected token a in JSON at position 2\n",
    "1.base.json.html:21 {a: 12, b: 5}\n",
    "1.base.json.html:23 字符串：{ 'a': 'abc', 'b': 5 }转换发生异常：SyntaxError: Unexpected token ' in JSON at position 2\n",
    "1.base.json.html:21 {a: \"abc\", b: 5}\n",
    "```\n",
    "\n",
    "**字符串和Json相互转换**：\n",
    "1. **字符串转换成Json对象：`JSON.parse()`**\n",
    "2. **Json对象转换成字符串：`JSON.stringify()`**\n",
    "\n",
    "```javascript\n",
    "let json1 = { name: \"小明\", age: 23, test: \"我X!@#$%^&*(-_-)=+\" };\n",
    "let new_str = JSON.stringify(json1);\n",
    "console.log(new_str);\n",
    "\n",
    "// encodeURI对有些特殊符号并不会编码替换\n",
    "let urlstr = encodeURIComponent(`https://www.baidu.com/s?wd=${new_str}`);\n",
    "console.log(urlstr);\n",
    "console.log(decodeURIComponent(urlstr));\n",
    "```\n",
    "输出：\n",
    "```\n",
    "{\"name\":\"小明\",\"age\":23,\"test\":\"我X!@#$%^&*(-_-)=+\"}\n",
    "\n",
    "https://www.baidu.com/s?wd=%7B%22name%22:%22%E5%B0%8F%E6%98%8E%22,%22age%22:23,%22test%22:%22%E6%88%91X!@#$%25%5E&*(-_-)=+%22%7D\n",
    "\n",
    "https%3A%2F%2Fwww.baidu.com%2Fs%3Fwd%3D%7B%22name%22%3A%22%E5%B0%8F%E6%98%8E%22%2C%22age%22%3A23%2C%22test%22%3A%22%E6%88%91X!%40%23%24%25%5E%26*(-_-)%3D%2B%22%7D\n",
    "\n",
    "https://www.baidu.com/s?wd={\"name\":\"小明\",\"age\":23,\"test\":\"我X!@#$%^&*(-_-)=+\"}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## 5.字符串系\n",
    "\n",
    "### 1.字符串模板\n",
    "\n",
    "#### 渲染变量\n",
    "\n",
    "省的一个个去拼接了（PS：`反单引号`）\n",
    "```javascript\n",
    "let [name,age]=[\"小明\",23];\n",
    "\n",
    "// 我叫小明,我今年23\n",
    "console.log(`我叫${name},我今年${age}`);\n",
    "```\n",
    "\n",
    "**Python3用起来差不多**：\n",
    "```py\n",
    "name, age = \"小明\", 23\n",
    "\n",
    "# 我叫小明,今年23\n",
    "print(f\"我叫{name},今年{age}\")\n",
    "```\n",
    "\n",
    "#### 保持原有格式\n",
    "\n",
    "**注意一点：换行内容如果不想要空格就顶行写**\n",
    "```javascript\n",
    "console.log(`我叫：\n",
    "小明\n",
    "今年：\n",
    "23`);\n",
    "```\n",
    "输出：\n",
    "```\n",
    "我叫：\n",
    "小明\n",
    "今年：\n",
    "23\n",
    "```\n",
    "\n",
    "Python就换成了`\"\"\"`\n",
    "```py\n",
    "print(\"\"\"我叫：\n",
    "小明\n",
    "今年：\n",
    "23\n",
    "\"\"\")\n",
    "```\n",
    "\n",
    "### 2.开头结尾方法\n",
    "\n",
    "#### 基本用法\n",
    "\n",
    "```javascript\n",
    "let url = \"https://www.baidu.com\";\n",
    "\n",
    "if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n",
    "    console.log(\"B/S\");\n",
    "}\n",
    "\n",
    "if (url.endsWith(\".com\")) {\n",
    "    console.log(\".com\")\n",
    "}\n",
    "```\n",
    "\n",
    "#### Python3\n",
    "\n",
    "```py\n",
    "url = \"https://www.baidu.com\"\n",
    "\n",
    "if url.startswith(\"https://\") or url.startswith(\"http://\"):\n",
    "    print(\"B/S\")\n",
    "\n",
    "if url.endswith(\".com\"):\n",
    "    print(\".com\")\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ⅱ.ES6~OOP\n",
    "\n",
    "参考文档：https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes\n",
    "\n",
    "以前JS的OOP严格意义上还是一个个函数，只是人为给他含义罢了，现在是真的支持了，**性能和语法都优化了**\n",
    "\n",
    "## 1.封装\n",
    "\n",
    "```javascript\n",
    "// People后面没有括号\n",
    "class People {\n",
    "    // 构造函数\n",
    "    constructor(name, age) {\n",
    "        this.name = name;\n",
    "        this.age = age;\n",
    "    }\n",
    "    show() {\n",
    "        console.log(`我叫：${this.name}，今年${this.age}`);\n",
    "    }\n",
    "    // 静态方法\n",
    "    static hello() {\n",
    "        console.log(\"Hello World!\");\n",
    "    }\n",
    "}\n",
    "// new别忘记了\n",
    "let xiaoming = new People(\"小明\", 23);\n",
    "xiaoming.show(); //我叫：小明，今年23\n",
    "// xiaoming.hello(); 这个不能访问（PY可以）\n",
    "People.hello(); //Hello World!\n",
    "```\n",
    "\n",
    "看看Python怎么定义的：（self每个都要写）\n",
    "\n",
    "```py\n",
    "class People(object):\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "    def show(self):\n",
    "        print(f\"我叫：{self.name}，今年：{self.age}\")\n",
    "\n",
    "    @classmethod\n",
    "    def hello(cls):\n",
    "        print(\"Hello World!\")\n",
    "\n",
    "\n",
    "xiaoming = People(\"小明\", 23)\n",
    "xiaoming.show()  # 我叫：小明，今年：23\n",
    "# 这个虽然可以访问到，但我一直都不建议这么用（不然用其他语言会混乱崩溃的）\n",
    "xiaoming.hello()  # Hello World!\n",
    "People.hello()  # Hello World!\n",
    "```\n",
    "\n",
    "PS：JS后来居上，看起来语法比PY更简洁点了\n",
    "\n",
    "## 2.继承\n",
    "\n",
    "```javascript\n",
    "class Teacher extends People {\n",
    "    constructor(name, age, work) {\n",
    "        super(name, age); // 放上面\n",
    "        this.work = work;\n",
    "    }\n",
    "    show_job() {\n",
    "        console.log(`我是做${this.work}工作的`);\n",
    "    }\n",
    "}\n",
    "let xiaozhang = new Teacher(\"小张\", 25, \"思想教育\");\n",
    "xiaozhang.show(); // 我叫：小张，今年25\n",
    "xiaozhang.show_job(); // 我是做思想教育工作的\n",
    "Teacher.hello(); // Hello World!\n",
    "```\n",
    "\n",
    "> PS：**如果子类中存在构造函数，则需要在使用`this`之前首先调用`super()`**\n",
    "\n",
    "看看Python语法：\n",
    "```py\n",
    "class Teacher(People):\n",
    "    def __init__(self, name, age, work):\n",
    "        self.work = work\n",
    "        super().__init__(name, age)\n",
    "\n",
    "    def show_job(self):\n",
    "        print(f\"我是做{self.work}工作的\")\n",
    "\n",
    "\n",
    "xiaozhang = Teacher(\"小张\", 25, \"思想教育\")\n",
    "xiaozhang.show()  # 我叫：小张，今年：25\n",
    "xiaozhang.show_job()  # 我是做思想教育工作的\n",
    "Teacher.hello()  # Hello World!\n",
    "```\n",
    "\n",
    "## 3.多态\n",
    "\n",
    "多态这方面和Python一样，有点后劲不足，只能伪实现，不能像Net、Java这些这么强大\n",
    "\n",
    "```javascript\n",
    "class Animal {\n",
    "    constructor(name) {\n",
    "        this.name = name;\n",
    "    }\n",
    "    run() {\n",
    "        console.log(`${this.name}会跑`);\n",
    "    }\n",
    "}\n",
    "class Dog extends Animal {\n",
    "    run() {\n",
    "        console.log(`${this.name}会飞快的跑着`);\n",
    "    }\n",
    "}\n",
    "// 借助一个方法来实现多态\n",
    "let run = obj => {\n",
    "    obj.run()\n",
    "}\n",
    "run(new Animal(\"动物\")); // 动物会跑\n",
    "run(new Dog(\"小狗\")); // 小狗会飞快的跑着\n",
    "```\n",
    "\n",
    "Python也半斤八两，十分相似\n",
    "```py\n",
    "class Animal(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def run(self):\n",
    "        print(f\"{self.name}会跑\")\n",
    "\n",
    "class Dog(Animal):\n",
    "    def run(self):\n",
    "        print(f\"{self.name}会飞快的跑着\")\n",
    "\n",
    "# 借助一个方法来实现多态\n",
    "def run(obj):\n",
    "    obj.run()\n",
    "\n",
    "run(Animal(\"动物\"))  # 动物会跑\n",
    "run(Dog(\"小狗\"))  # 小狗会飞快的跑着\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## 业余拓展\n",
    "\n",
    "### 函数中的`bind`\n",
    "\n",
    "> **直接指定函数中`this`的值，防止改变**\n",
    "\n",
    "**如果指定一个事件执行函数的时候，class里面的this会变化，这时候不想外面套一层方法就可以使用bind**\n",
    "\n",
    "```javascript\n",
    "class People {\n",
    "    constructor(name, age) {\n",
    "        this.name = name;\n",
    "        this.age = age;\n",
    "    }\n",
    "    show() {\n",
    "        console.log(this);\n",
    "        console.log(`我叫：${this.name}，今年${this.age}`);\n",
    "    }\n",
    "}\n",
    "\n",
    "let p = new People(\"小明\", 23);\n",
    "\n",
    "// 按照道理应该可以，但是因为this变了，所以不行\n",
    "//document.onclick = p.show; // 我叫：undefined，今年undefined\n",
    "\n",
    "// 原来写法：外面包裹一层方法\n",
    "//document.onclick = () => p.show(); // 我叫：小明，今年23\n",
    "\n",
    "// 简写：bind\n",
    "document.onclick = p.show.bind(p); // 我叫：小明，今年23\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "### 几个验证\n",
    "\n",
    "**小验证**：直接指定函数中`this`的值，防止改变\n",
    "```javascript\n",
    "function show() {\n",
    "    console.log(this);\n",
    "}\n",
    "document.onclick = show; // document\n",
    "document.onclick = show.bind(\"mmd\"); // String {\"mmd\"}\n",
    "```\n",
    "\n",
    "**小验证**：`箭头函数的优先级比bind高`\n",
    "```javascript\n",
    "document.onclick = function () {\n",
    "    let arr = [1, 2, 3, 4];\n",
    "    arr.show = () => {\n",
    "        console.log(this); // document\n",
    "    }\n",
    "    arr.show.bind(\"mmd\"); // 箭头函数的优先级比bind高\n",
    "    arr.show();\n",
    "}\n",
    "```\n",
    "\n",
    "### ES6继承的不足\n",
    "1. 只支持静态方法，不支持静态属性\n",
    "2. class中不能定义私有变量和函数\n",
    "    - class中定义的所有方法都会被放倒原型当中，都会被子类继承，而属性都会作为实例属性挂到this上\n",
    "\n",
    "课后拓展：`https://www.jianshu.com/p/5cb692658704`\n",
    "\n",
    "### Python3与NetCore\n",
    "\n",
    "**Python3 与 C# 面向对象之～封装**：\n",
    "https://www.cnblogs.com/dotnetcrazy/p/9202988.html\n",
    "\n",
    "**Python3 与 C# 面向对象之～继承与多态**：\n",
    "https://www.cnblogs.com/dotnetcrazy/p/9219226.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.OOP实战\n",
    "\n",
    "**微信小程序出来后，组件化的概念越来越火（可以理解为模块化），结合`OOP`真的很方便**\n",
    "\n",
    "### 4.1.React组件引入\n",
    "\n",
    "先看个`React`的基础案例（结合`Next.js`更爽）\n",
    "```html\n",
    "<!DOCTYPE html>\n",
    "<html>\n",
    "<head>\n",
    "    <meta charset=\"utf-8\" />\n",
    "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n",
    "    <title>React组件化</title>\n",
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n",
    "    <script src=\"./js/react/16.6.3/react.production.min.js\"></script>\n",
    "    <script src=\"./js/react-dom/16.6.3/react-dom.production.min.js\"></script>\n",
    "    <script src=\"./js/babel-core/5.8.38/browser.min.js\"></script>\n",
    "    <!-- 注意下类型是\"text/babel\" -->\n",
    "    <script type=\"text/babel\">\n",
    "    window.onload=function () {\n",
    "        let item = document.getElementById(\"test\");\n",
    "        ReactDOM.render(\n",
    "            <strong>公众号：逸鹏说道</strong>,\n",
    "            item\n",
    "        );\n",
    "    };\n",
    "    </script>\n",
    "</head>\n",
    "<body>\n",
    "    <div id=\"test\"></div>\n",
    "</body>\n",
    "</html>\n",
    "```\n",
    "输出：**公众号：逸鹏说道**\n",
    "\n",
    "### 扩展说明\n",
    "\n",
    "**业余扩展：`AMD`、`CMD`、`CJS`、`UMD`**：\n",
    "https://blog.csdn.net/yikewang2016/article/details/79358563\n",
    "\n",
    "#### 1.React and babel\n",
    "\n",
    "**PS：`React 16.x`开始**：\n",
    "1. `react.js` ==> `react.development.js`\n",
    "    - **`react.min.js` ==> `react.production.min.js`**\n",
    "2. `react-dom.js` ==> `react-dom.development.js`\n",
    "    - **`react-dom.min.js` ==> `react-dom.production.min.js`**\n",
    "\n",
    "**PS：如果自己找JS，搜索三个包：`react`、`react-dom`、`babel-core 5.x`**（JSX）\n",
    "\n",
    "#### 2.npm and cnpm\n",
    "\n",
    "**npm国内镜像**：`https://npm.taobao.org`\n",
    "\n",
    "配置一下即可：**`npm install -g cnpm --registry=https://registry.npm.taobao.org`**\n",
    "\n",
    "然后就可以把`cnpm`当作`npm`来用了，比如上面三个js文件：\n",
    "1. **`cnpm install react`**\n",
    "2. **`cnpm install react-dom`**\n",
    "3. **`cnpm i babel-core@old`**\n",
    "\n",
    "**PS：`i`是`install`的简写，`-g`是安装到全局环境中，不加就只是安装到当前目录**\n",
    "\n",
    "---\n",
    "\n",
    "### 4.2.OOP组件\n",
    "\n",
    "#### 1.OOP改造\n",
    "\n",
    "用`OOP`来改造一下上面的案例：（`ReactDOM`在执行`render`渲染`<MyTest>`标签的时候会返回，`MyTest类`里面的`return值`）\n",
    "```html\n",
    "<!DOCTYPE html>\n",
    "<html>\n",
    "<head>\n",
    "    <meta charset=\"utf-8\" />\n",
    "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n",
    "    <title>OOP组件</title>\n",
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n",
    "    <script src=\"./js/react/16.6.3/react.production.min.js\"></script>\n",
    "    <script src=\"./js/react-dom/16.6.3/react-dom.production.min.js\"></script>\n",
    "    <script src=\"./js/babel-core/5.8.38/browser.min.js\"></script>\n",
    "    <script type=\"text/babel\">\n",
    "        class MyTest extends React.Component{\n",
    "            // 可以省略\n",
    "            constructor(...args){\n",
    "                super(...args);\n",
    "            }\n",
    "            // 必须定义的方法\n",
    "            render(){\n",
    "                return <strong>公众号：逸鹏说道</strong>;\n",
    "            }\n",
    "        }\n",
    "        window.onload=()=>{\n",
    "            let test = document.getElementById(\"test\");\n",
    "            ReactDOM.render(\n",
    "                <MyTest></MyTest>,\n",
    "                test\n",
    "            );\n",
    "        }\n",
    "    </script>\n",
    "</head>\n",
    "<body>\n",
    "    <div id=\"test\"></div>\n",
    "</body>\n",
    "</html>\n",
    "```\n",
    "输出：**公众号：逸鹏说道**\n",
    "\n",
    "#### 语法衍生\n",
    "\n",
    "好处通过这个案例可能还看不出来，但是你想一下：当那些常用功能模板成为一个个自己的组件时，你的每一次前端开发是多么幸福的事情？\n",
    "\n",
    "再语法衍生一下，来个稍微动态一点案例：\n",
    "\n",
    "```html\n",
    "<!DOCTYPE html>\n",
    "<html>\n",
    "<head>\n",
    "    <meta charset=\"utf-8\" />\n",
    "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n",
    "    <title>OOP组件</title>\n",
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n",
    "    <script src=\"./js/react/16.6.3/react.production.min.js\"></script>\n",
    "    <script src=\"./js/react-dom/16.6.3/react-dom.production.min.js\"></script>\n",
    "    <script src=\"./js/babel-core/5.8.38/browser.min.js\"></script>\n",
    "    <script type=\"text/babel\">\n",
    "        class Item extends React.Component{\n",
    "            render(){\n",
    "                console.log(this);\n",
    "                return <strong>{this.props.str}</strong>;\n",
    "            }\n",
    "        }\n",
    "        window.onload=()=>{\n",
    "            ReactDOM.render(<Item str=\"我叫小明\"></Item>,document.getElementById(\"test\"));\n",
    "        }\n",
    "    </script>\n",
    "</head>\n",
    "<body>\n",
    "    <div id=\"test\"></div>\n",
    "</body>\n",
    "</html>\n",
    "```\n",
    "输出：(**两种方式传参：1.字符串，2.{}表达式**)\n",
    "![我叫小明](https://img2018.cnblogs.com/blog/1127869/201812/1127869-20181203230341926-1140414187.png)\n",
    "\n",
    "#### 自定义组件\n",
    "\n",
    "有上面两个铺垫，现在做个自己的小组件：\n",
    "```html\n",
    "<!DOCTYPE html>\n",
    "<html>\n",
    "\n",
    "<head>\n",
    "    <meta charset=\"utf-8\" />\n",
    "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n",
    "    <title>OOP组件</title>\n",
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n",
    "    <script src=\"./js/react/16.6.3/react.production.min.js\"></script>\n",
    "    <script src=\"./js/react-dom/16.6.3/react-dom.production.min.js\"></script>\n",
    "    <script src=\"./js/babel-core/5.8.38/browser.min.js\"></script>\n",
    "    <script type=\"text/babel\">\n",
    "        class Item extends React.Component{\n",
    "            render(){\n",
    "                console.log(this);\n",
    "                return <li><strong>{this.props.str}</strong></li>;\n",
    "            }\n",
    "        }\n",
    "        class MyList extends React.Component{            \n",
    "            render(){\n",
    "                console.log(this);\n",
    "                return <ul>\n",
    "                {this.props.names.map(x=> <Item str={x}></Item>)}\n",
    "                </ul>\n",
    "            }\n",
    "        }\n",
    "        window.onload=()=>{\n",
    "            let test = document.getElementById(\"test\");\n",
    "            ReactDOM.render(\n",
    "                // 这边的值可以从后台获取\n",
    "                <MyList names={[\"Golang\",\"Python\",\"NetCore\",\"JavaScript\"]}></MyList>,\n",
    "                test\n",
    "            );\n",
    "        }\n",
    "    </script>\n",
    "</head>\n",
    "\n",
    "<body>\n",
    "    <div id=\"test\"></div>\n",
    "</body>\n",
    "</html>\n",
    "```\n",
    "输出：(**两种方式传参：1.字符串，2.{}表达式**)\n",
    "![我叫小明](https://img2018.cnblogs.com/blog/1127869/201812/1127869-20181203230632079-1417076319.png)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ⅲ.ES6～EXT\n",
    "\n",
    "课后拓展：`https://www.babeljs.cn/learn-es2015/`\n",
    "\n",
    "## 1.异步\n",
    "\n",
    "最后方案和写法类似于`Python`、`NetCore`，都是`async`和`await`，前面是一步步引入（本质）\n",
    "\n",
    "### 1.1.JQ引入\n",
    "\n",
    "#### 常见情景\n",
    "\n",
    "基于`JQ`的异步操作很常见，比如：\n",
    "```javascript\n",
    "console.log(\"--------------------\")\n",
    "$.ajax({\n",
    "    url: \"./data/user.json\",\n",
    "    dataType: \"json\",\n",
    "    success(data) {\n",
    "        console.log(data);\n",
    "    }, error(ex) {\n",
    "        console.log(\"请求失败\");\n",
    "    }\n",
    "});\n",
    "console.log(\"--------------------\")\n",
    "```\n",
    "输出：（的确是异步操作，不等结果返回就先执行下面语句了）\n",
    "```\n",
    "--------------------\n",
    "--------------------\n",
    "{Name: \"小明\", Age: 23}\n",
    "```\n",
    "\n",
    "#### 探讨本质\n",
    "\n",
    "那么它的本质是什么呢？来看看返回什么：\n",
    "```javascript\n",
    "let p1 = $.ajax({\n",
    "    url: \"./data/user.json\",\n",
    "    dataType: \"json\"\n",
    "});\n",
    "console.log(p1);\n",
    "```\n",
    "输出：（其实本质也是一个封装版的**`Promise`**）\n",
    "![JQ](https://img2018.cnblogs.com/blog/1127869/201812/1127869-20181204153211060-99248661.png)\n",
    "\n",
    "**用等价写法改装一下**：（`then两个方法，一个处理成功，一个处理失败`）\n",
    "```javascript\n",
    "let p1 = \\$.ajax({\n",
    "    url: \"./data/user.json\",\n",
    "    dataType: \"json\"\n",
    "});\n",
    "\n",
    "// 不存在的文件\n",
    "let p2 = \\$.ajax({\n",
    "    url: \"./data/mmd.json\",\n",
    "    dataType: \"json\"\n",
    "});\n",
    "\n",
    "p1.then(data => console.log(data), ex => console.log(\"请求失败\"));\n",
    "p2.then(data => console.log(data), ex => console.log(\"请求失败\"));\n",
    "```\n",
    "输出：(忽略上面的`\\`我的渲染有的问题，需要转义一下)\n",
    "```\n",
    "{Name: \"小明\", Age: 23}\n",
    "请求失败\n",
    "```\n",
    "\n",
    "### 1.2.Promise\n",
    "\n",
    "简单的说就是：**Promise：用同步的方式去写异步**\n",
    "\n",
    "语法：`Promise(()=>{});`\n",
    "\n",
    "有点类似于`NetCore`的`Task`==> `Task.Run(()=>{});`\n",
    "\n",
    "上面的那个例子本质上相当于：\n",
    "```javascript\n",
    "let p1 = new Promise((resolve, reject) => {\n",
    "    $.ajax({\n",
    "        url: \"./data/user.json\",\n",
    "        dataType: \"json\",\n",
    "        success(data) {\n",
    "            resolve(data);\n",
    "        },\n",
    "        error(ex) {\n",
    "            reject(ex);\n",
    "        }\n",
    "    });\n",
    "});\n",
    "p1.then(data => console.log(data), ex => console.log(\"请求失败\"));\n",
    "```\n",
    "\n",
    "业务上难免都有相互依赖，以前写法也只能在`sucess`回调函数里面一层层的嵌套\n",
    "\n",
    "一个是比较麻烦，还有就是看起来特别不方便，一不小心就搞错了，现在就简单多了，then里面直接处理\n",
    "\n",
    "咋一看，没啥好处啊？而且还复杂了，其实当任务多的时候好处就来了\n",
    "\n",
    "比如**结合JQ来模拟一个`事务`性的案例**：\n",
    "```javascript\n",
    "let p1 = $.ajax({ url: \"./data/user.json\", dataType: \"json\" });\n",
    "let p2 = $.ajax({ url: \"./data/list.txt\", dataType: \"json\" });\n",
    "let p3 = $.ajax({ url: \"./data/package.json\", dataType: \"json\" });\n",
    "\n",
    "// 进行一系列处理（有一个失败都会直接进入错误处理）\n",
    "Promise.all([p1, p2, p3]).then(arr => {\n",
    "    // 这时候返回的是一个数组\n",
    "    console.log(arr);\n",
    "}, ex => {\n",
    "    console.error(ex);\n",
    "});\n",
    "```\n",
    "输出：\n",
    "![Promise](https://img2018.cnblogs.com/blog/1127869/201812/1127869-20181204162338089-937554813.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.迭代器\n",
    "\n",
    "这个简单过一下，和Python没有太多不同\n",
    "\n",
    "### 2.1.引入\n",
    "\n",
    "用`function*`来定义一个迭代器\n",
    "```javascript\n",
    "function* show() {\n",
    "    console.log(\"a\");\n",
    "    yield \"1\";\n",
    "    console.log(\"b\");\n",
    "    yield \"2\";\n",
    "    console.log(\"c\");\n",
    "    return \"d\";\n",
    "}\n",
    "\n",
    "let gen = show();\n",
    "// 每一次next都执行到下一个yield停止\n",
    "console.log(gen.next());\n",
    "// 返回值.value 可以得到yield返回的值\n",
    "console.log(gen.next().value);\n",
    "// done==true的时候代表迭代结束\n",
    "console.log(gen.next());\n",
    "```\n",
    "输出：\n",
    "```\n",
    "a\n",
    "{value: \"1\", done: false}\n",
    "b\n",
    "2\n",
    "c\n",
    "{value: \"d\", done: true}\n",
    "```\n",
    "\n",
    "### 2.2.遍历\n",
    "\n",
    "#### JavaScript\n",
    "\n",
    "通过上面输出可以瞬间知道退出条件：`done: true`，那么遍历方式就来了：\n",
    "```javascript\n",
    "function* show() {\n",
    "    yield \"1\";\n",
    "    yield \"2\";\n",
    "    return \"d\";\n",
    "}\n",
    "let gen = show();\n",
    "\n",
    "while (true) {\n",
    "    let result = gen.next();\n",
    "    if (result.done) {\n",
    "        console.log(`返回值：${result.value}`);\n",
    "        break;\n",
    "    } else {\n",
    "        console.log(result.value);\n",
    "    }\n",
    "}\n",
    "```\n",
    "输出：\n",
    "```\n",
    "1\n",
    "2\n",
    "返回值：d\n",
    "```\n",
    "\n",
    "JS也提供了**`for of`**来遍历：\n",
    "```javascript\n",
    "for (let item of show()) {\n",
    "    console.log(item);\n",
    "}\n",
    "```\n",
    "\n",
    "#### Python3\n",
    "\n",
    "大体上差不多，结束条件是触发`StopIteration`异常\n",
    "```py\n",
    "def show():\n",
    "    yield \"1\"\n",
    "    yield \"2\"\n",
    "    return \"d\"\n",
    "\n",
    "gen = show()\n",
    "\n",
    "while True:\n",
    "    try:\n",
    "        print(next(gen))\n",
    "    except StopIteration as ex:\n",
    "        print(f\"返回值：{ex.value}\")\n",
    "        break\n",
    "\n",
    "for item in show():\n",
    "    print(item)  # 1 2\n",
    "```\n",
    "输出：\n",
    "```\n",
    "1\n",
    "2\n",
    "返回值：d\n",
    "1\n",
    "2\n",
    "```\n",
    "\n",
    "### 2.3.传参\n",
    "\n",
    "#### JavaScript\n",
    "\n",
    "```javascript\n",
    "function* show2() {\n",
    "    a = yield \"111\";\n",
    "    console.log(a);\n",
    "    b = yield a;\n",
    "    console.log(b);\n",
    "    c = yield b;\n",
    "    console.log(c);\n",
    "    return \"over\";\n",
    "}\n",
    "\n",
    "let gen = show2();\n",
    "// 和Python一样，第一个不传参\n",
    "console.log(gen.next());\n",
    "console.log(gen.next(\"aaa\"));\n",
    "console.log(gen.next(\"bbb\"));\n",
    "console.log(gen.next(\"ccc\"));\n",
    "```\n",
    "输出：\n",
    "```\n",
    "{value: \"111\", done: false}\n",
    "aaa\n",
    "{value: \"aaa\", done: false}\n",
    "bbb\n",
    "{value: \"bbb\", done: false}\n",
    "ccc\n",
    "{value: \"over\", done: true}\n",
    "```\n",
    "\n",
    "#### Python3\n",
    "\n",
    "传参Python是使用的send方法，其实next本质也是send，这个之前讲过了：\n",
    "```py\n",
    "def show():\n",
    "    a = yield \"111\"\n",
    "    print(a)\n",
    "    b = yield a\n",
    "    print(b)\n",
    "    c = yield b\n",
    "    print(c)\n",
    "    return \"over\"\n",
    "\n",
    "gen = show()\n",
    "# 第一个不传参\n",
    "print(next(gen))  # gen.send(None)\n",
    "print(gen.send(\"aaa\"))\n",
    "print(gen.send(\"bbb\"))\n",
    "try:\n",
    "    print(gen.send(\"ccc\"))\n",
    "except StopIteration as ex:\n",
    "    print(ex.value)\n",
    "```\n",
    "输出：\n",
    "```\n",
    "111\n",
    "aaa\n",
    "bbb\n",
    "bbb\n",
    "ccc\n",
    "over\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.`async/await`\n",
    "\n",
    "如果你现在还没有用过`async`和`await`的话...需要好好提升下了，还是通俗说下吧：\n",
    "1. await你可以理解为：等待后面异步方法的结果，这时候的结果就是你需要的\n",
    "2. async你可以理解为：使用了await的方法需要特殊标记一下\n",
    "\n",
    "### 3.1.引入\n",
    "\n",
    "ES6出来前，我们用异步一般是这么用的：\n",
    "1. **和下文JS不关联的外部JS，都打个异步标签来异步加载**\n",
    "2. `<script src=\"./js/test.js\" async></script>`\n",
    "\n",
    "现在可以正经的使用了，继续把上面那个例子衍生下：（之前用`then(()=>{},()=>{})`，现在可以使用`async`和`await`来简化）\n",
    "\n",
    "```javascript\n",
    "async function show(url) {\n",
    "    let data = await $.ajax({ url: url, dataType: 'json' });\n",
    "    console.log(data)\n",
    "}\n",
    "show(\"./data/list.txt\")\n",
    "```\n",
    "输出：\n",
    "```\n",
    "[1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
    "```\n",
    "\n",
    "### 3.2.批量\n",
    "\n",
    "就算是批量任务也不用那么麻烦了：\n",
    "```javascript\n",
    "let show = async (urls) => {\n",
    "    for (const url of urls) {\n",
    "        let data = await $.ajax({ url: url, dataType: \"json\" });\n",
    "        console.log(data);\n",
    "    }\n",
    "}\n",
    "\n",
    "show([\"./data/user.json\", \"./data/list.txt\", \"./data/package.json\"]);\n",
    "```\n",
    "输出：\n",
    "```\n",
    "{Name: \"小明\", Age: 23}\n",
    "[1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
    "{name: \"data\", version: \"0.1.0\", description: \"测试\", main: \"index.js\", scripts: {…}, …}\n",
    "```\n",
    "\n",
    "### 3.3.匿名\n",
    "\n",
    "**应用常见其实很多，比如执行某个事件、比如引入某个外部JS...**，eg：\n",
    "\n",
    "**test.js**\n",
    "```javascript\n",
    "(async () => {\n",
    "    let data = await $.ajax({ url: \"./data/list.txt\", dataType: 'json' });\n",
    "    console.log(data);\n",
    "})();\n",
    "```\n",
    "\n",
    "HTML中引用一下：`<script src=\"./js/test.js\" async></script>`\n",
    "\n",
    "输出：\n",
    "```\n",
    "[1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
    "```\n",
    "\n",
    "### 3.4.嵌套\n",
    "\n",
    "和`NetCore`一样，可以嵌套使用的，`await`的对象一般都是`Promise`或者同是`async`修饰的方法\n",
    "\n",
    "**举个例子**：\n",
    "\n",
    "`test.js`：\n",
    "```javascript\n",
    "let show = async (urls) => {\n",
    "    for (const url of urls) {\n",
    "        let data = await $.ajax({ url: url, dataType: \"json\" });\n",
    "        console.log(data);\n",
    "    }\n",
    "    return \"ok\";\n",
    "}\n",
    "\n",
    "let test = async () => {\n",
    "    let result = await show([\"./data/user.json\", \"./data/list.txt\", \"./data/package.json\"]);\n",
    "    return result;\n",
    "}\n",
    "```\n",
    "页面\n",
    "```html\n",
    "<script src=\"./js/test.js\"></script>\n",
    "<script>\n",
    "    (async () => {\n",
    "        let data = await test();\n",
    "        console.log(data);\n",
    "    })();\n",
    "</script>\n",
    "```\n",
    "输出：\n",
    "```\n",
    "{Name: \"小明\", Age: 23}\n",
    "[1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
    "{name: \"data\", version: \"0.1.0\", description: \"测试\", main: \"index.js\", scripts: {…}, …}\n",
    "ok\n",
    "```\n",
    "\n",
    "### Python3\n",
    "\n",
    "Python3.7开始，语法才开始简洁：\n",
    "\n",
    "```py\n",
    "import asyncio\n",
    "\n",
    "# 模拟一个异步操作\n",
    "async def show():\n",
    "    await asyncio.sleep(1)\n",
    "    return \"写完文章早点睡觉哈~\"\n",
    "\n",
    "# 定义一个异步方法\n",
    "async def test(msg):\n",
    "    print(msg)\n",
    "    return await show()\n",
    "\n",
    "# Python >= 3.7\n",
    "result = asyncio.run(test(\"这是一个测试\"))\n",
    "print(result)\n",
    "\n",
    "# Python >= 3.4\n",
    "loop = asyncio.get_event_loop()\n",
    "result = loop.run_until_complete(test(\"这是一个测试\"))\n",
    "print(result)\n",
    "loop.close()\n",
    "```\n",
    "输出：\n",
    "```\n",
    "这是一个测试\n",
    "写完文章早点睡觉哈~\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.模块化\n",
    "\n",
    "这个ES6里面有，但是浏览器并没有完全支持，所以现在大家还是用**`Require.js`**和`Sea.js`更多点\n",
    "\n",
    "简单看看就行：扩展链接 ~ `https://www.cnblogs.com/diligenceday/p/5503777.html`\n",
    "\n",
    "模块定义：\n",
    "```javascript\n",
    "export { a, test, user }\n",
    "\n",
    "let test = () => {\n",
    "    console.log(\"test\");\n",
    "}\n",
    "\n",
    "let user = () => {    \n",
    "    console.log(\"user\");\n",
    "    return \"小明\";\n",
    "}\n",
    "\n",
    "let a = 1;\n",
    "```\n",
    "\n",
    "导入模块：\n",
    "```javascript\n",
    "import { a, test, user } from \"./mod.js\"\n",
    "console.log(a);\n",
    "test();\n",
    "console.log(user());\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
